
// Copyright (C) 2009-2011 Luca Piccioni
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//   
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.IO;
using System.Diagnostics;

using Derm.Render;

namespace Derm.Raster
{
	/// <summary>
	/// Raster image.
	/// </summary>
	/// <remarks>
	/// <para>
	/// A RasterImage allow to store and process pixel data. The image is composed by a rectangle of
	/// pixels, which format determine the pixel size.
	/// </para>
	/// </remarks>
	public class RasterImage<T> : Image where T : IColor, new()
	{
		#region Constructor & Destructor

		/// <summary>
		/// Construct a RasterImage.
		/// </summary>
		public RasterImage() : this(0, 0)
		{

		}

		/// <summary>
		/// Construct a RasterImage.
		/// </summary>
		/// <param name="w">
		/// A <see cref="System.Int32"/> that specifies the image width, in pixels.
		/// </param>
		/// <param name="h">
		/// A <see cref="System.Int32"/> that specifies the image height, in pixels.
		/// </param>
		public RasterImage(uint w, uint h) : this(w, h, 0)
		{

		}

		/// <summary>
		/// Construct a RasterImage.
		/// </summary>
		/// <param name="w">
		/// A <see cref="System.Int32"/> that specifies the image width, in pixels.
		/// </param>
		/// <param name="h">
		/// A <see cref="System.Int32"/> that specifies the image height, in pixels.
		/// </param>
		/// <param name="flags">
		/// A <see cref="Image.ModifierFlags"/> that specifies special image handling.
		/// </param>
		public RasterImage(uint w, uint h, ModifierFlags flags) : base(flags)
		{
			// Allocate this RasterImage
			AllocatePixelData(w, h);
		}

		#endregion

		#region Image Buffer Management

		/// <summary>
		/// Allocate pixel data buffer.
		/// </summary>
		/// <param name="w">
		/// A <see cref="System.Int32"/>
		/// </param>
		/// <param name="h">
		/// A <see cref="System.Int32"/>
		/// </param>
		public override void AllocatePixelData(uint w, uint h)
		{
			// Set pixel size
			mPixelSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));

			// Allocate room for pixel data
			if ((w > 0) && (h > 0)) {
				// One layer image
				LayerCount = 1;
				// Store image extents
				Width = w; Height = h;
				// Allocate layer pixels
				mImage = new T[h, w];
			} else {
				// No layers
				LayerCount = 0;
				// Store image extents (zero)
				Width = w; Height = h;
				// Deallocate layer pixels
				mImage = null;
			}
		}

		/// <summary>
		/// RasterImage pixel data.
		/// </summary>
		protected T[,] mImage = null;

		#endregion

		#region Image Overrides

		/// <summary>
		/// Image pixel format.
		/// </summary>
		/// <returns>
		/// It returns a <see cref="Pixel.Type"/> that specifies the image color resolution.
		/// </returns>
		public override Pixel.Type PixelFormat
		{
			get {
				// IColor interface allow pixel format query (hardcoded in struct implementation)
				return (new T().PixelType);
			}
		}

		/// <summary>
		/// Pixel data buffer.
		/// </summary>
		public override object GetPixelData(uint layer)
		{
			if (layer != 0)
				throw new ArgumentException("invalid layer " + layer);

			return (mImage);
		}

		/// <summary>
		/// Pixel data accessor.
		/// </summary>
		/// <param name="layer">
		/// A <see cref="System.Int32"/> indicating the layer to fetch pixel data.
		/// </param>
		/// <param name="x">
		/// A <see cref="System.Int32"/> indicating the horizontal coordinate of the pixel. The
		/// left corners has the coordinate 0.
		/// </param>
		/// <param name="y">
		/// A <see cref="System.Int32"/> indicating the vertical coordinate of the pixel. The
		/// bottom corners has the coordinate 0.
		/// </param>
		/// <remarks>
		/// </remarks>
		public override IColor this[uint layer, uint x, uint y]
		{
			get {
				if (layer != 0)
					throw new ArgumentException("invalid layer " + layer);
				if (x > Width)
					throw new ArgumentException("out of range X coordinate " + x);
				if (y > Height)
					throw new ArgumentException("out of range Y coordinate " + y);

				return (mImage[y, x]);
			}
			set {
				T pProto = new T();

				Debug.Assert(layer == 0, "RasterImage.Accessor[int,int,int]", "Invalid layer " + layer);
				Debug.Assert((x >= 0) && (x < Width), "RasterImage.Accessor[int,int,int]", "Invalid X coordinate " + x);
				Debug.Assert((y >= 0) && (y < Height), "RasterImage.Accessor[int,int,int]", "Invalid Y coordinate " + y);

				for (int i = 0; i < Pixel.GetComponentsCount(PixelFormat); i++)
					mImage[y, x][i] = value[i];
			}
		}

		#endregion
	}
}
